package model;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;

import org.jdom.Document;

import net.DataSender;
import server.SystemConstants;


public class Room {
	private LinkedList<String> registered;
	private HashMap<String, UserInfo> login;
	private HashMap<String, DataSender> senders;
	
	private class UserInfo{
		private boolean loggedIn;
		private boolean chatting;
		private String ip;
		
		public UserInfo(boolean l, boolean c, String ip){
			loggedIn = l;
			chatting = c;
			this.ip = ip;
		}
	}
	
	public synchronized void updateRegistered() {
		registered = new LinkedList<String>();
		File file = new File(SystemConstants.REGISTERED_FILE_NAME);
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));
			String s = null;
			while((s = reader.readLine()) != null){
				registered.add(s);
			}
			reader.close();
			
			// for debug purpose
			System.err.println("The registered user names are:");
			for(String i : registered){
				System.err.println(i);
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	/*
	 * should be called when a user tries to register or login
	 */
	public synchronized boolean isRegistered(String name){
		return registered.contains(name);
	}

	public synchronized boolean register(String name){
		if(isRegistered(name) == false){			
			try {
				FileWriter writer = new FileWriter(SystemConstants.REGISTERED_FILE_NAME, true);
				writer.write(name + "\n");
				writer.close();
				registered.add(name);
				login.put(name, new UserInfo(false, false, null));
				
				return true;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return false;
			}
			
		} else {
			return false;
		}
	}
	
	public Room(){
		registered = new LinkedList<String>();
		login = new HashMap<String, UserInfo>();
		senders = new HashMap<String, DataSender>();
		
		File file = new File(SystemConstants.REGISTERED_FILE_NAME);
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));
			String s = null;
			while((s = reader.readLine()) != null){
				registered.add(s);
				login.put(s, new UserInfo(false, false, null));
			}
			
			reader.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public synchronized boolean isLoggedIn(String name){
		return ((UserInfo) login.get(name)).loggedIn;
	}
	
	/*
	 * The client side should maintain if the user had logged in or not
	 * function is called assuming that the user is nog logged in
	 * check if the user has registered, if so, log in, return true, else return false
	 */
	public synchronized boolean logIn(String name, String ip, DataSender sender){
		if(isRegistered(name) && (isLoggedIn(name) == false)){
			UserInfo info = new UserInfo(true, false, ip);
			login.put(name, info);
			senders.put(name, sender);
			
			return true;
		} else {
			return false;
		}
	}
	
	public synchronized DataSender getSender(String name){
		return senders.get(name);
	}
	
	public synchronized void logOut(String name){
		UserInfo info = new UserInfo(false, false, null);
		login.put(name, info);
		senders.put(name, null);
	}
	
	public void broadCast(Document doc){
		Iterator<Entry<String, DataSender>> itr = senders.entrySet().iterator();
		while(itr.hasNext()){
			Map.Entry<String, DataSender> entry = (Map.Entry<String, DataSender>)itr.next();
			DataSender sender = entry.getValue();
			if(sender != null){
				sender.add(doc);
			}
		}
	}
	
	public synchronized LinkedList<User> getLoggedUsers(){
		LinkedList<User> users = new LinkedList<User>();
		Iterator<Entry<String, UserInfo>> itr = login.entrySet().iterator();
		while(itr.hasNext()){
			Map.Entry<String, UserInfo> entry = (Map.Entry<String, UserInfo>) itr.next();
			UserInfo info = (UserInfo) entry.getValue();
			String name = (String) entry.getKey();
			if(info.loggedIn){
				users.add(new User(name, info.ip));
			}
		}
		
		return users;
	}
	
	public synchronized boolean isChatting(String name){
		UserInfo info = (UserInfo) login.get(name);
		return info.chatting;
	}
	
	public synchronized void setChatting(String name, boolean c){
		UserInfo info = (UserInfo) login.get(name);
		info.chatting = c;
	}
}
